package com.bc.trade.controller;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.bc.common.CommonEnum.OrderStatus;
import com.bc.common.CommonEnum.Resp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bc.common.PayType;
import com.bc.common.ThreadShare;
import com.bc.common.message.AppidPayReq;
import com.bc.common.message.AppidWxgjPayReq;
import com.bc.common.message.AppidWxgjPayResp;
import com.bc.common.message.BaseReq;
import com.bc.common.message.BaseResp;
import com.bc.common.message.DFReq;
import com.bc.common.message.TransferQrcodeReq;
import com.bc.common.message.WxgjClearingReq;
import com.bc.trade.channel.ChannelFactory;
import com.bc.trade.channel.IChannel;
import com.bc.trade.config.R;
import com.bc.trade.config.SystemConfig;
import com.bc.trade.message.BindBankCardReq;
import com.bc.trade.message.BindBankCardVerifyReq;
import com.bc.trade.message.QueryBalanceReq;
import com.bc.trade.message.QueryCardInfoReq;
import com.bc.trade.message.QueryOrderReq;
import com.bc.trade.message.QueryOrderResp;
import com.bc.trade.message.QuickPayReq;
import com.bc.trade.message.QuickPaySetReq;
import com.bc.trade.message.RefundReq;
import com.bc.trade.message.SendSMSReq;
import com.bc.trade.message.UnionPayReq;
import com.bc.trade.model.Org;
import com.bc.trade.model.TradeOrder;
import com.bc.trade.service.RouteService;
import com.bc.trade.util.Aes;
import com.bc.trade.util.Rsa;
import com.bc.trade.util.TripleDes;
import com.bc.trade.model.Merch;
import com.bc.trade.model.MerchRole;
import com.bc.trade.model.MerchUser;
import com.fs.common.extend.FSController;
import com.fs.common.util.FSHttp;
import com.fs.common.util.FSJson;
import com.fs.common.util.FSLog;
import com.fs.common.util.FSMD5;
import com.fs.common.util.FSRSA;
import com.jfinal.aop.Enhancer;
import com.jfinal.kit.StrKit;

/**
 * 交易路由控制器, 统一对外提供接口
 *
 * @author Reed
 * @date 2017年9月25日
 */
public class RouteController extends FSController {

	private final String gethost = "www.qcurepay.com";
	private final String appid_ser = "3beb25d1f67076b0f3197ea00a99c4d5";
	private final String APPID = SystemConfig.channelConfig.get("wxgj_appid");
	private final String getOpenidUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
	private final String getOpenidUrl_2 = "https://api.weixin.qq.com/sns/oauth2/access_token";
	private final String getOpenidUrl_callbackPay = "http://" + gethost + "/trade/callbackAuthPay";
	private RouteService routeService = Enhancer.enhance(RouteService.class);

	public void route() {
		ThreadShare.ClientIP.set(getRequestIP());
		String reqString = getStringFromRequest();
		FSLog.api.info("接收到的请求数据 ------ > " + hide(reqString, "cardNo", "cvn2", "expired"));
		Map<String, String> reqMap = FSJson.toMap(reqString);
		BaseReq req = FSJson.toObject(reqString, BaseReq.class);
		BaseResp resp = commonValidate(req);
		if (resp.getRespCode().equals(Resp.Success.getCode())) {
			String safeKey = Org.dao.selectSafeKey(req.getOrgCode());
			String sign = FSMD5.sortSign(reqMap, safeKey);
			System.out.println(sign + "------------------");
			if (!sign.equals(req.getSign())) {
				resp.setCodeAndMsg(Resp.Fail.getCode(), R.MSG_SIGN_ERROR);
			} else {
				try {
					resp = process(reqString, req);
				} catch (Exception e) {
					e.printStackTrace();
					resp.setCodeAndMsg(Resp.Fail.getCode(), R.MSG_EXCEPTION);
					FSLog.api.error("接口处理发生异常 ->", e);
				}
			}

			resp.setSign(FSMD5.sortSign(resp, safeKey));
		}
		renderJson(resp);
	}

	/**
	 * 处理
	 *
	 * param reqMap
	 * @return
	 */
	private BaseResp process(String reqString, BaseReq req) throws Exception {
		switch (req.getPayType()) {
		case PayType.OWER_QUERY:
			return routeService.query(FSJson.toObject(reqString, QueryOrderReq.class));
		case PayType.ORDER_QUERY:
			return routeService.query(FSJson.toObject(reqString, QueryOrderReq.class));
		case PayType.UNION_PAY:
		case PayType.UNION_PAY_SUB:
			return routeService.unionpay(FSJson.toObject(reqString, UnionPayReq.class));
		case PayType.QUICK_PAY_SET:
			return routeService.quickPaySet(FSJson.toObject(reqString, QuickPaySetReq.class));
		case PayType.QUICK_PAY:
			return routeService.quickPay(FSJson.toObject(reqString, QuickPayReq.class));
		case PayType.REFUND:
			return routeService.refund(FSJson.toObject(reqString, RefundReq.class));
		case PayType.DF_PERSONAL:
		case PayType.DF_COMPANY:
			return routeService.df(FSJson.toObject(reqString, DFReq.class));
		case PayType.BALANCE_QUERY:
			return routeService.balanceQuery(FSJson.toObject(reqString, QueryBalanceReq.class));
		case PayType.SEND_SMS:
			return routeService.sendSMS(FSJson.toObject(reqString, SendSMSReq.class));
		case PayType.QUERY_CARD_INFO:
			return routeService.queryCardInfo(FSJson.toObject(reqString, QueryCardInfoReq.class));
		case PayType.TRANSFER_QRCODE:
			return routeService.transferQrcode(FSJson.toObject(reqString, TransferQrcodeReq.class));
		case PayType.BIND_CARD:
			return routeService.bindBankCard(FSJson.toObject(reqString, BindBankCardReq.class));
		case PayType.BIND_CARD_VERIFY:
			return routeService.bindBankCardVerify(FSJson.toObject(reqString, BindBankCardVerifyReq.class));
		case PayType.WECHAT_PUBLIC:
			return routeService.appidPay(FSJson.toObject(reqString, AppidPayReq.class));
		case PayType.ALIPAY_PUBLIC:
			return routeService.appidPay(FSJson.toObject(reqString, AppidPayReq.class));
		case PayType.WECHAT_QRCODE:
			return routeService.appidPay(FSJson.toObject(reqString, AppidPayReq.class));
		case PayType.ALIPAY_QRCODE:
			return routeService.appidPay(FSJson.toObject(reqString, AppidPayReq.class));
		case PayType.BLANK_NOTE:
			return routeService.blankNote(FSJson.toObject(reqString, com.bc.common.message.BlankNoteReq.class));
		case PayType.WXGJPAY_PUBLIC:
			return routeService.wxgjappidPay(FSJson.toObject(reqString, AppidWxgjPayReq.class));
		case PayType.WXGJPAY_QRCODE:
			return routeService.wxgjappidPay(FSJson.toObject(reqString, AppidWxgjPayReq.class));
		case PayType.WXGJPAY_MICORPAY:
			return routeService.wxgjappidPay(FSJson.toObject(reqString, AppidWxgjPayReq.class));
		case PayType.WXGJPAY_REFUND:
			return routeService.wxgjRefund(FSJson.toObject(reqString, RefundReq.class));
		case PayType.WXGJPAY_REFUND_QUERY:
			return routeService.wxgjRefundQuery(FSJson.toObject(reqString, RefundReq.class));
		case PayType.WXGJ_CLEARING_QCURE:
			return routeService.wxgjGetClearingData(FSJson.toObject(reqString, WxgjClearingReq.class));
		default:
			BaseResp resp = new BaseResp(req);
			resp.setCodeAndMsg(Resp.Fail.getCode(), "payType不存在");
			return resp;
		}
	}

	/**
	 * 验证
	 *
	 * @param req
	 * @return
	 */
	private BaseResp commonValidate(BaseReq req) {
		BaseResp resp = new BaseResp(req);
		if (StrKit.isBlank(req.getVersion())) {
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "版本号不允许为空");
		}
		if (StrKit.isBlank(req.getOrgCode())) {
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "机构号不允许为空");
		}
		if (StrKit.isBlank(req.getPayType())) {
			return resp.setCodeAndMsg(Resp.Fail.getCode(), "交易类别不允许为空");
		}
		return resp.setCodeAndMsg(Resp.Success.getCode(), Resp.Success.getMsg());
	}

	/**
	 * 隐藏敏感字段的值
	 *
	 * @param src
	 * @param keywords
	 * @return
	 */
	private String hide(String src, String... keywords) {
		char[] c = src.toCharArray();
		for (int i = 0; i < keywords.length; i++) {
			String keyword = "\"" + keywords[i] + "\":\"";
			int start = src.indexOf(keyword);
			if (start < 0) {
				continue;
			}

			int end = src.indexOf("\"", start + keyword.length());
			int length = end - start - keyword.length();
			for (int k = start + keyword.length(); k < end; k++) {
				if (length > 10) {
					if (k > start + keyword.length() + 5 && k < end - 4) {
						c[k] = '*';
					}
				} else {
					c[k] = '*';
				}
			}
		}
		return String.valueOf(c);
	}

	/**
	 * 获取IP地址
	 *
	 * @return
	 */
	private String getRequestIP() {
		HttpServletRequest request = getRequest();
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("Proxy-Client-IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("WL-Proxy-Client-IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getRemoteAddr();
		return ip;
	}

	// APP端登录接口
	public void appTologin() {
		String userName = getPara("userName");
		// String password = FSMD5.codeFor(getPara("password"));
		String password = (getPara("password"));
		FSLog.api.info("登录接口接收到的请求数据 ------ > " + userName);

		MerchUser loginUser = MerchUser.dao.loginFind(userName, password);
		JSONObject json = new JSONObject();
		if (loginUser != null) {
			if (loginUser.getEnable() == false) {
				json.put("resCode", "01");
				json.put("resMsg", "用户被禁用");
				renderJson(json.toString());
			} else {
				MerchRole role = MerchRole.dao.findById(loginUser.getRoleId());
				if (role == null) {
					json.put("resCode", "01");
					json.put("resMsg", "无角色用户,无法登录");
					renderJson(json.toString());
				} else {
					String orgKey = Org.dao.selectSafeKey(loginUser.getOrgCode());
					if (orgKey == null) {
						json.put("resCode", "01");
						json.put("resMsg", "没有此用户的机构信息!");
						renderJson(json.toString());
					} else {
						Merch merch = Merch.dao.selectFromRedis(loginUser.getMerchCode());
						json.put("resCode", "00");
						json.put("resMsg", "登录成功");
						json.put("info", JSON.toJSON(loginUser));
						json.put("key", orgKey);
						json.put("name", merch.getName());
						json.put("cointype", merch.getCointype());
						renderJson(json.toString());
					}
				}
			}
		} else {
			json.put("resCode", "01");
			json.put("resMsg", "用户名或者密码错误!");
			renderJson(json.toString());
		}
	}

	public void orderPublic() {
		String orderNO = getPara("orderNo");
		String callurl = getOpenidUrl_callbackPay;
		String Encallurl = null;
		try {
			Encallurl = URLEncoder.encode(callurl, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		StringBuffer strbuff = new StringBuffer();
		strbuff.append("appid=" + APPID + "&redirect_uri=" + Encallurl + "&response_type=code&scope=snsapi_base&state="
				+ orderNO + "&connect_redirect=1#wechat_redirect");

		String okurl = getOpenidUrl + "?" + strbuff.toString();
		System.out.println("支付接口前重定向的URL:" + okurl);
		// POST GET
		this.redirect(okurl);
	}

	public void callbackAuthPay() {
		String alldata = this.getPara("code");
		String orderNo = this.getPara("state");

		String geturl = (getOpenidUrl_2 + "?appid=" + APPID + "&secret=" + appid_ser + "&code=" + alldata
				+ "&grant_type=authorization_code");
		// 获取openid的请求地址
		String res = null;
		try {
			res = FSHttp.postString(geturl, "");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		/*
		 * { "access_token":"ACCESS_TOKEN", "expires_in":7200,
		 * "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
		 */
		System.out.println("支付接口前返回的openid:" + res);
		if (res == null || 0 == res.length()) {
			renderHtml("A-订单号:" + orderNo + "使用的 openid 不存在!");
			return;
		}
		JSONObject json = JSON.parseObject(res);
		String openid = json.getString("openid");

		if (openid == null || 0 == openid.length()) {
			renderHtml("A-订单号获取openid:" + res + "使用的 openid 不存在!");
			return;
		}

		FSLog.api.info("A-订单号获取openid:" + res + "使用的 openid 获取成功!");

		TradeOrder order = TradeOrder.dao.selectByOrderNoForUpdate(orderNo);
		if (order == null) {
			renderHtml("A-订单号:" + orderNo + "不存在!");
			return;
		} else {
			if ((null != order.getOpenid()) && !("".equals(order.getOpenid()))) {
				renderHtml("A-订单号:" + orderNo + "已经被处理，请不要重复处理!");
				return;
			}
			if (!PayType.WXGJPAY_PUBLIC.equals(order.getPayType())) {
				renderHtml("A-订单号:" + orderNo + "支付类型错误!");
				return;
			}
			order.setOpenid(openid);
			IChannel channel = ChannelFactory.get(order.getChannelCode());
			AppidWxgjPayResp resp = null;
			try {
				FSLog.api.info("A-订单:" + order.getMerchOrderNo() + "发起支付交易.........");
				resp = channel.wxgjappidPayOrder(order);
				if ("00".equals(resp.getRespCode())) {
					String payinfo = resp.getPayInfo();
					if (payinfo != null) {
						this.setAttr("sayHello", payinfo);
						this.setAttr("merchOrder", order.getMerchOrderNo());
						this.setAttr("trorder", order.getOrderNo());
						this.render("hello.html");
					}
				}else {
					String payinfo = resp.getPayInfo();
					this.setAttr("sayHello", payinfo);
					String amt = "" + order.getAmount().intValue();
					//FSLog.api.info("1.--------------需要显示的金额:" + amt);
					String showamt = null;
					try {
						showamt = changeF2Y(amt);
					} catch (Exception e) {
						// TODO: handle exception
					}
					setAttr("outTradeNo", order.getMerchOrderNo());
					setAttr("status", "2");
					setAttr("amount", showamt);
					setAttr("payInfo", resp.getRespMsg());
					order.setRespMsg(resp.getRespMsg());
					setAttr("tip", "支付失败!");
					setAttr("coinType", order.getCoinType());
					if(order.getReturnUrl()!=null && 0 < order.getReturnUrl().length()) {
						setAttr("resUrl", order.getReturnUrl());
					}
					render("payStatus.html");
				}
			} catch (Exception e) {
				FSLog.api.error("支付宝生活号及微信公众号支付:" + e);
				resp.setCodeAndMsg(Resp.Fail.getCode(), Resp.Fail.getMsg());
			} finally {
				order.update();
			}
			return;
		}

	}

	public void ourWxFont() {
		String merchOrderNo = getPara("merchOrder");
		String orderNo = getPara("orderNo");
		FSLog.api.info("内部查询:" + merchOrderNo + ";" + orderNo);
		TradeOrder order = TradeOrder.dao.selectByOrderNoForUpdate(orderNo);
		if (merchOrderNo == null) {
			return;
		}
		if (!merchOrderNo.equals(order.getMerchOrderNo())) {
			return;
		}

		QueryOrderResp resp = null;
		String showamt = null;
		if (OrderStatus.Success.getValue().equals(order.getOrderStatus())) {
			resp = new QueryOrderResp();
			resp.setRespCode("00");
			resp.setOriginalRespCode("00");

			String amt = "" + order.getAmount().intValue();
			FSLog.api.info("1.--------------需要显示的金额:" + amt);
			try {
				showamt = changeF2Y(amt);
			} catch (Exception e) {
				// TODO: handle exception
			}
			FSLog.api.info("2.--------------需要显示的金额:" + showamt);
		} else {
			IChannel channel = ChannelFactory.get(order.getChannelCode());
			try {
				resp = channel.query(order);
				String amt = "" + order.getAmount().intValue();
				FSLog.api.info("1.--------------需要显示的金额:" + amt);
				showamt = changeF2Y(amt);
				FSLog.api.info("2.--------------需要显示的金额:" + showamt);
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
		if ("00".equals(resp.getOriginalRespCode()) && "00".equals(resp.getRespCode())) {
			setAttr("outTradeNo", order.getMerchOrderNo());
			setAttr("status", "1");
			setAttr("amount", showamt);
			setAttr("payInfo", "");
			setAttr("coinType", order.getCoinType());
			setAttr("tip", "支付成功!");
		} else {
			setAttr("outTradeNo", order.getMerchOrderNo());
			setAttr("status", "2");
			setAttr("amount", showamt);
			setAttr("payInfo", "未支付");
			setAttr("tip", "支付失败!");
			setAttr("coinType", order.getCoinType());
		}
		if(order.getReturnUrl()!=null && 0 < order.getReturnUrl().length()) {
			setAttr("resUrl", order.getReturnUrl());
			redirect(order.getReturnUrl());
		}else {
			render("payStatus.html");
		}
	}

	/** 金额为分的格式 */
	public static final String CURRENCY_FEN_REGEX = "\\-?[0-9]+";

	private String changeF2Y(String amount) throws Exception {
		if (!amount.matches(CURRENCY_FEN_REGEX)) {
			throw new Exception("金额格式有误");
		}
		return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString();
	}

	public void testopenid() {
		JSONObject json = new JSONObject();
		json.put("xx", "xxx");
		json.put("yy", "yyyy");

		this.setAttr("sayHello", json.toJSONString());

		String merchOrder = "KMF885599250414997504";
		String orderNo = "HKDF885599250832998400";

		this.setAttr("merchOrder", merchOrder);
		this.setAttr("trorder", orderNo);
		this.render("NewFile.html");

//		setAttr("outTradeNo", "1111111111111");
//		setAttr("status", "1");
//		setAttr("amount", "10.77");
//		setAttr("coinType", "HKD");
//		render("payStatus.html");
	}

	public boolean isJson(String content) {
		try {
			JSONObject jsonStr = JSONObject.parseObject(content);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	private static String easy_path_test = "d:\\easy.pfx";
	private static String easy_path = "/usr/certs/easy.pfx";

	public static void main(String args[]) {
		String reqString = "SXObSQv/+HlJ26hU8pcxEQuOuJlJa9R0ulmrPO5nq+xbN8JKLY1WRN9UbE7dd7SOWJH01/5Op2YLHIG4Uod9E+49EMuVJJz53eeoiDQl2sYi+EfZc2aK0KvfLuMXVC74mfdFdvg00+oyu12OWumVEP9NGXrPLF+JbT45C33mqN8=|pQPbazBAXr/y2/j4YN0msW3hj3LTfTBWqvzlHoE+TeWe/S7xpnU+dNzueXTIeY8WlgeEcYKDjsrGEaELUom3xMyjU0LKY5IJFW88N3r/l9swURsnjWH8oNHHJTMvhzO3J4BJDz0PQiufu5/7AesVZ4WspZY9AgU5pMEwhh4HdtL/0x2ex/HUQfFR6BcReREPS+CE8VxGqli4K4xoiVHmkffOEOwLR9t2XJnl9WkHEWjfkZ94IgTV+U0fkA7/Lo+8Cv3ng3XZg136FO2E40pwgESADZp9UYHIAfvAju4W1eTrL9U8d7/9/KDu6aI2ul8P5liInWeXEF1FwKPzITbbJVFH27YULnyvwi75oAAeZEq+hyqP7ywOuOCPzOeMKuKvc5+Abqr8ML8Bcx0JBNsK7Vvyi+ew2jWYe2g384VUPUlys5pRdwzM9+L+E1kBObgcQCJsHtRbEv9H0GYOj3+sUEDhz+BmAEMmAFbEHvVlQyM5GfiLGd1RFdh2ThgDuDZjNCkZcJHeBd0JqTkpsObC79Pj7o2dLipMZ3oUERZFCKZ3GHFnUMKMrfLKKDbo6r3mPP4PVYtwNpsQKjURUsjKwEyCXVk/MJsh99DUBWBkWsPT4+6NnS4qTGd6FBEWRQimdxhxZ1DCjK3yyig26Oq95nJDdakj1lfKArH5xCaUUgDNcWE9vywBLeA+rSq0hdxHuN7CE4CwZiJlOkmIe7nAR7iXVzJJoi3GnT7zQg6TrQqjZZiRTjWSmqf6ZfelOwcVsVd/AqD2Cv92HH9GeFXVFnKDBMPT580eTnVdvRuCyteR6bjjQtP9osx4UYmSGGTcSqMtSI+dSf1AXIGX6vaaVzw6ZpvoWAlvEKAoohCi8uOBGj5lGVPqKmrANbHOxy+4cXI8NHFgVBBCBgV/kqlBaQs5aaXKCPPG6wiqCTUs0W0==";

		String aeskey = Aes.decrypt("F5634D02D5C58DC7340DC7160B4463FA");

		String keyEnc = reqString.split("\\|")[0];
		String dataEnc = reqString.split("\\|")[1];
		String key = null;
		try {
			key = Rsa.decrypt(keyEnc, easy_path_test, aeskey);
			String dataTmp = TripleDes.decrypt(key, dataEnc);
			Map<String, String> reqMap = FSJson.toMap(dataTmp);

			FSLog.api.info("Visa 解密后数据 ------ > " + dataTmp);
			FSLog.api.info("Visa 解密后Map ------ > " + reqMap.toString());
			if (reqMap.containsKey("serviceCode") && "0200".equals(reqMap.get("serviceCode"))) {
				// routeService.visapay(reqMap);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
